﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Domain.Abstract;
using Domain.Entities;
using WebUI.Controllers;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using WebUI.Models;
using WebUI.HtmlHelpers;
using WebUI.Models;


namespace UnitTests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void Can_Paginate()
        {
            //Arrange
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] { 
            new Product {ProductID = 1, Name = "P1"}, 
            new Product {ProductID = 2, Name = "P2"}, 
            new Product {ProductID = 3, Name = "P3"}, 
            new Product {ProductID = 4, Name = "P4"}, 
            new Product {ProductID = 5, Name = "P5"} 
            }.AsQueryable());

            ProductController controller = new ProductController(mock.Object);
            controller.PageSize = 3;

            //Act
            ProductListViewModel result = (ProductListViewModel)controller.List(null, 2).Model;

            //Assert
            Product[] productArray = result.Products.ToArray();
            Assert.IsTrue(productArray.Length == 2);
            Assert.AreEqual(productArray[0].Name, "P4");
            Assert.AreEqual(productArray[1].Name, "P5");
        }

        [TestMethod]
        public void Can_Generate_Page_Links()
        {
            // Arrange - define an HTML helper - we need to do this 
            // in order to apply the extension method 
            HtmlHelper myHelper = null;
            // Arrange - create PagingInfo data 
            PagingInfo pagingInfo = new PagingInfo
            {
                CurrentPage = 2,
                TotalsItems = 28,
                ItemPerPage = 10
            };
            // Arrange - set up the delegate using a lambda expression 
            Func<int, string> pageUrlDelegate = i => "Page" + i;
            // Act 
            MvcHtmlString result = myHelper.PageLinks(pagingInfo, pageUrlDelegate);
            // Assert 
            Assert.AreEqual(result.ToString(), @"<a href=""Page1"">1</a>"
            + @"<a class=""selected"" href=""Page2"">2</a>"
            + @"<a href=""Page3"">3</a>");
        }

        [TestMethod]
        public void Can_Send_Pagination_View_Model()
        {
            //Arrange
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            mock.Setup(p => p.Products).Returns(new Product[]{
                new Product{ProductID = 1, Name = "Ipod touch 1"},
                new Product{ProductID = 2, Name = "Ipod touch 2"},
                new Product{ProductID = 3, Name = "Ipod touch 3"},
                new Product{ProductID = 4, Name = "Ipod touch 4"},
                new Product{ProductID = 5, Name = "Ipod touch 5"},
            }.AsQueryable);

            //Action
            ProductListViewModel model = (ProductListViewModel)new ProductController(mock.Object) { PageSize = 3 }.List(null, 2).Model;
            PagingInfo pageInfo = model.PagingInfo;

            //Assert
            Assert.AreEqual(mock.Object.Products.ElementAt<Product>(4).ProductID, model.Products.ToArray()[1].ProductID);
            Assert.AreEqual(pageInfo.TotalsItems, 5);
            Assert.AreEqual(pageInfo.TotalPages, 2);
            Assert.AreEqual(pageInfo.CurrentPage, 2);
            Assert.AreEqual(pageInfo.ItemPerPage, 3);
        }

        [TestMethod]
        public void Can_Filter_Product()
        {
            //Arrange
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            mock.Setup(p => p.Products).Returns(new Product[] {new Product{ProductID = 1, Name = "Ipod touch 1", Category = "Cat1"},
                new Product{ProductID = 2, Name = "Ipod touch 2", Category = "Cat2"},
                new Product{ProductID = 3, Name = "Ipod touch 3", Category = "Cat3"},
                new Product{ProductID = 4, Name = "Ipod touch 4", Category = "Cat4"},
                new Product{ProductID = 5, Name = "Ipod touch 5", Category = "Cat5"}, }.AsQueryable());

            //Act
            ProductController controller = new ProductController(mock.Object) { PageSize = 3 };
            ProductListViewModel model = (ProductListViewModel)controller.List("Cat2", 1).Model;

            //Assert
            Assert.AreEqual("Cat2", model.CurrentCategory);
            Assert.AreEqual(2, model.Products.ToArray()[0].ProductID);
        }

        [TestMethod]
        public void Can_Create_Categories()
        {
            // Arrange 
            // - create the mock repository 
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] { 
            new Product {ProductID = 1, Name = "P1", Category = "Apples"}, 
            new Product {ProductID = 2, Name = "P2", Category = "Apples"}, 
            new Product {ProductID = 3, Name = "P3", Category = "Plums"}, 
            new Product {ProductID = 4, Name = "P4", Category = "Oranges"}, 
            }.AsQueryable());

            //Arrange
            // create controller
            NavController nav = new NavController((IProductRepository)mock.Object);

            //Act.
            IEnumerable<string> categories = (IEnumerable<string>)nav.Menu().Model;
            Assert.AreEqual(categories.Count(), 3);
            Assert.AreEqual(categories.ElementAt(0),"Apples");
            Assert.AreEqual(categories.ElementAt(1), "Oranges");
            Assert.AreEqual(categories.ElementAt(2), "Plums");
        }

        [TestMethod]
        public void Indicates_Selected_Category() { 
            //Arrange
            // - create the mock repository
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] { 
            new Product {ProductID = 1, Name = "P1", Category = "Apples"}, 
            new Product {ProductID = 2, Name = "P2", Category = "Apples"}, 
            new Product {ProductID = 3, Name = "P3", Category = "Plums"}, 
            new Product {ProductID = 4, Name = "P4", Category = "Oranges"}, 
            }.AsQueryable());

            //Arrange - create the folder
            NavController target = new NavController(mock.Object);

            //Arrange - add the category selected
            string categorySelected = "Apples";

            //Action
            string result = target.Menu(categorySelected).ViewBag.SelectedCategory;

            //Assert
            Assert.AreEqual(categorySelected, result);
        }

        [TestMethod]
        public void Can_Add_New_Lines() { 
            //Arrange 
            Product product1 = new Product {ProductID = 1, Name = "P1", Category = "Apples"};
            Product product2 = new Product { ProductID = 2, Name = "P2", Category = "Apples" };
            Cart cart = new Cart();

            //Act;
            cart.AddItem(product1, 1);
            cart.AddItem(product2, 2);
            CartLine[] result = cart.lines().ToArray();

            //Assert
            Assert.AreEqual(result[0].Product.ProductID, 1);
            Assert.AreEqual(result[1].Product.ProductID, 2);
        }

        [TestMethod]
        public void Can_Add_Quantity_For_Existing_Files() {             
            // Arrange - create some test products 
            Product p1 = new Product { ProductID = 1, Name = "P1" }; 
            Product p2 = new Product { ProductID = 2, Name = "P2" }; 
            // Arrange - create a new cart 
            Cart target = new Cart(); 
            // Act 
            target.AddItem(p1, 1); 
            target.AddItem(p2, 1); 
            target.AddItem(p1, 10);
            CartLine[] result = target.lines().OrderBy(p => p.Product.ProductID).ToArray();

            //Assert
            Assert.AreEqual(result[0].Quantity, 11);
            Assert.AreEqual(result[1].Quantity, 1);
        }

        [TestMethod]
        public void Can_Remove_Lines() {
            // Arrange - create some test products 
            Product p1 = new Product { ProductID = 1, Name = "P1" };
            Product p2 = new Product { ProductID = 2, Name = "P2" };
            Product p3 = new Product { ProductID = 3, Name = "P3" };
            // Arrange - create a new cart 
            Cart target = new Cart();
            // Arrange - add some products to the cart 
            target.AddItem(p1, 1);
            target.AddItem(p2, 3);
            target.AddItem(p3, 5);
            target.AddItem(p2, 1);

            // Act 
            target.RemoveLine(p2); 

            //Assert
            Assert.AreEqual(target.lines().Where(p => p.Product == p2).Count(), 0);
            Assert.AreEqual(target.lines().Count(),2);
        }

        [TestMethod]
        public void Can_Calculate_Total(){
            // Arrange - create some test products 
            Product p1 = new Product { ProductID = 1, Name = "P1", Price = 100M };
            Product p2 = new Product { ProductID = 2, Name = "P2", Price = 50M };

            // Arrange - create a new cart 
            Cart target = new Cart(); 

            //Act
            target.AddItem(p1, 1);
            target.AddItem(p2, 1);
            target.AddItem(p1, 3);
            decimal result = target.ComputeTotalValue();

            //Assert
            Assert.AreEqual(result, 450M);
        }
    }
}
